// import com.alibaba.druid.DbType_ptr;
// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveInsert;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveMultiInsertStatement;
// import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExpr;
// import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleExpr;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitorAdapter;
// import com.alibaba.druid.sql.repository.SchemaObject;
// import com.alibaba.druid.sql.repository.SchemaRepository_ptr;
// import com.alibaba.druid.stat.TableStat_ptr;
// import com.alibaba.druid.stat.TableStat_ptr.TableStat_Column_ptr;
// import com.alibaba.druid.stat.TableStat_ptr.TableStat_Condition;
// import com.alibaba.druid.stat.TableStat_ptr.TableStat_Mode_ptr;
// import com.alibaba.druid.stat.TableStat_ptr.TableStat_Relationship;
// import com.alibaba.druid.util.FnvHash;

// import java.util.*;
#pragma once
#include "SQLASTVisitorAdapter.h"
#include <map>
#include <set>
#include "../../stat/TableStat.h"
#include "../dialect/mysql/visitor/MySqlASTVisitorAdapter.h"
#include "../dialect/oracle/visitor/OracleASTVisitorAdapter.h"
#include "../ast/statement/SQLCreateTableStatement.h"
#include "../dialect/hive/stmt/HiveCreateTableStatement.h"

class SchemaStatVisitor
    : virtual public SQLASTVisitorAdapter
{
public:
  SchemaRepository_ptr repository;

  SQLName_list_ptr originalTables;

  // std::shared_ptr<std::map<TableStat_Name, TableStat_ptr>> tableStats;
  std::shared_ptr<std::map<std::string, TableStat_ptr>> tableStats;
  std::map<long, TableStat_Column_ptr> columns;
  TableStat_Condition_list_ptr conditions;
  std::shared_ptr<std::set<TableStat_Relationship_ptr>> relationships;
  TableStat_Column_list_ptr orderByColumns;
  std::shared_ptr<std::set<TableStat_Column_ptr>> groupByColumns;
  SQLAggregateExpr_list_ptr aggregateFunctions;
  SQLMethodInvokeExpr_list_ptr functions;

  Object_list_ptr parameters;

  TableStat_Mode_ptr mode;

  DbType_ptr dbType;

  SchemaStatVisitor();

  SchemaStatVisitor(SchemaRepository_ptr repository);

  SchemaStatVisitor(DbType_ptr dbType);

  SchemaStatVisitor(Object_list_ptr parameters);

  SchemaStatVisitor(DbType_ptr dbType, Object_list_ptr parameters);

  SchemaStatVisitor(SchemaRepository_ptr repository, Object_list_ptr parameters);

  SHAREDOBJECT(SchemaStatVisitor);
  SchemaRepository_ptr getRepository();

  void setRepository(SchemaRepository_ptr repository);

  Object_list_ptr getParameters();

  void setParameters(Object_list_ptr parameters);

  TableStat_ptr getTableStat(string_ptr tableName);

  TableStat_ptr getTableStat(SQLName_ptr tableName);

  TableStat_Column_ptr addColumn(string_ptr tableName, string_ptr columnName);

  TableStat_Column_ptr addColumn(SQLName_ptr table, string_ptr columnName);

  string_ptr handleName(string_ptr ident);

  TableStat_Mode_ptr getMode()
  {
    return mode;
  }

  void setModeOrigin(SQLObject_ptr x);

  TableStat_Mode_ptr setMode(SQLObject_ptr x, TableStat_Mode_ptr mode);

  bool visitOrderBy(SQLIdentifierExpr_ptr x);

  bool visitOrderBy(SQLPropertyExpr_ptr x);

  bool visitOrderBy(SQLIntegerExpr_ptr x);

  void orderByAddColumn(string_ptr table, string_ptr columnName, SQLObject_ptr expr);

  bool visit(SQLOrderBy_ptr x);

  bool visit(SQLOver_ptr x);

  bool visit(SQLWindow_ptr x);

  SQLASTVisitor_ptr createOrderByVisitor(SQLOrderBy_ptr x);

  std::shared_ptr<std::set<TableStat_Relationship_ptr>> getRelationships()
  {
    return relationships;
  }

  TableStat_Column_list_ptr getOrderByColumns()
  {
    return orderByColumns;
  }

  std::shared_ptr<std::set<TableStat_Column_ptr>> getGroupByColumns()
  {
    return groupByColumns;
  }

  TableStat_Condition_list_ptr getConditions()
  {
    return conditions;
  }

  SQLAggregateExpr_list_ptr getAggregateFunctions()
  {
    return aggregateFunctions;
  }

  bool visit(SQLBetweenExpr_ptr x);

  bool visit(SQLBinaryOpExpr_ptr x);

  void handleRelationship(SQLExpr_ptr left, string_ptr operator_, SQLExpr_ptr right);

  void handleCondition(SQLExpr_ptr expr, string_ptr operator_, SQLExpr_ptr values);
  void handleCondition(SQLExpr_ptr expr, string_ptr operator_, SQLExpr_list_ptr valueExprs);
  void handleCondition(SQLExpr_ptr expr, string_ptr operator_)
  {
    SQLExpr_list_ptr valueExprs = std::make_shared<std::list<SQLExpr_ptr>>();
    handleCondition(expr, operator_, valueExprs);
  }

  DbType_ptr getDbType();

  TableStat_Column_ptr getColumn(SQLExpr_ptr expr);

  SQLExpr_ptr unwrapExpr(SQLExpr_ptr expr);

  // @Override
  bool visit(SQLTruncateStatement_ptr x);

  // @Override
  bool visit(SQLDropViewStatement_ptr x);

  // @Override
  bool visit(SQLDropTableStatement_ptr x);

  // @Override
  bool visit(SQLInsertStatement_ptr x);

  static void putAliasMap(std::shared_ptr<std::map<string_ptr, string_ptr>> aliasMap, string_ptr name, string_ptr value);

  void accept(SQLObject_ptr x);

  // void accept(List<? extends SQLObject_ptr> nodes)
  void accept(SQLObject_list_ptr nodes);

  bool visit(SQLSelectQueryBlock_ptr x);

  static bool isParam(SQLIdentifierExpr_ptr x);

  void endVisit(SQLSelectQueryBlock_ptr x);

  bool visit(SQLJoinTableSource_ptr x);

  bool visit(SQLPropertyExpr_ptr x);

  bool isPseudoColumn(long hash)
  {
    return false;
  }

  bool visit(SQLIdentifierExpr_ptr x);

  bool isParentSelectItem(SQLObject_ptr parent);

  bool isParentGroupBy(SQLObject_ptr parent);

  void setColumn(SQLExpr_ptr x, TableStat_Column_ptr column);

  TableStat_Column_ptr handleUnknownColumn(string_ptr columnName);

  bool visit(SQLAllColumnExpr_ptr x);

  void statAllColumn(SQLAllColumnExpr_ptr x, SQLTableSource_ptr tableSource);

  void statAllColumn(SQLAllColumnExpr_ptr x, SQLExprTableSource_ptr tableSource);

  // std::shared_ptr<std::map<TableStat_Name, TableStat_ptr>> getTables()
  std::shared_ptr<std::map<std::string, TableStat_ptr>> getTables()
  {
    return tableStats;
  }

  bool containsTable(string_ptr tableName);

  bool containsColumn(string_ptr tableName, string_ptr columnName);

  TableStat_Column_list_ptr getColumns();

  TableStat_Column_ptr getColumn(string_ptr tableName, string_ptr columnName);

  bool visit(SQLSelectStatement_ptr x);

  void endVisit(SQLSelectStatement_ptr x)
  {
  }

  // @Override
  bool visit(SQLWithSubqueryClause_Entry_ptr x);

  bool visit(SQLSubqueryTableSource_ptr x);

  bool isSimpleExprTableSource(SQLExprTableSource_ptr x);

  TableStat_ptr getTableStat(SQLExprTableSource_ptr tableSource);

  TableStat_ptr getTableStatWithUnwrap(SQLExpr_ptr expr);

  bool visit(SQLExprTableSource_ptr x);

  bool isSubQueryOrParamOrVariant(SQLIdentifierExpr_ptr identifierExpr);

  bool isSubQueryOrParamOrVariant(SQLPropertyExpr_ptr x);

  bool visit(SQLSelectItem_ptr x);

  bool visit(SQLSelect_ptr x);

  bool visit(SQLAggregateExpr_ptr x);

  bool visit(SQLMethodInvokeExpr_ptr x);

  bool visit(SQLUpdateStatement_ptr x);

  bool visit(SQLUpdateSetItem_ptr x);

  bool visit(SQLDeleteStatement_ptr x);

  bool visit(SQLInListExpr_ptr x);

  // @Override
  bool visit(SQLInSubQueryExpr_ptr x);

  void endVisit(SQLDeleteStatement_ptr x);

  void endVisit(SQLUpdateStatement_ptr x);

  bool visit(SQLCreateTableStatement_ptr x);

  bool visit(SQLColumnDefinition_ptr x);

  // @Override
  bool visit(SQLCallStatement_ptr x)
  {
    return false;
  }

  // @Override
  void endVisit(SQLCommentStatement_ptr x)
  {
  }

  // @Override
  BOOL_ptr visit(SQLCommentStatement_ptr x)
  {
    return BOOL::FALSE;
  }

  bool visit(SQLCurrentOfCursorExpr_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableAddColumn_ptr x);

  // @Override
  void endVisit(SQLAlterTableAddColumn_ptr x)
  {
  }

  // @Override
  bool visit(SQLRollbackStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLCreateViewStatement_ptr x);

  bool visit(SQLAlterViewStatement_ptr x);

  // @Override
  bool visit(SQLAlterTableDropForeignKey_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLUseStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableDisableConstraint_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableEnableConstraint_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableStatement_ptr x);

  // @Override
  bool visit(SQLAlterTableDropConstraint_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLDropIndexStatement_ptr x);

  // @Override
  bool visit(SQLCreateIndexStatement_ptr x);

  // @Override
  bool visit(SQLForeignKeyImpl_ptr x);

  // @Override
  bool visit(SQLDropSequenceStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLDropTriggerStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLDropUserStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLGrantStatement_ptr x);

  // @Override
  bool visit(SQLRevokeStatement_ptr x);

  // @Override
  bool visit(SQLDropDatabaseStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableAddIndex_ptr x);

  bool visit(SQLCheck_ptr x);

  bool visit(SQLDefault_ptr x);

  bool visit(SQLCreateTriggerStatement_ptr x);

  bool visit(SQLDropFunctionStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLDropTableSpaceStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLDropProcedureStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableRename_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLArrayExpr_ptr x);

  // @Override
  bool visit(SQLOpenStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLFetchStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLDropMaterializedViewStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLShowMaterializedViewStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLRefreshMaterializedViewStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLCloseStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLCreateProcedureStatement_ptr x);

  // @Override
  bool visit(SQLCreateFunctionStatement_ptr x);

  // @Override
  bool visit(SQLBlockStatement_ptr x);

  // @Override
  bool visit(SQLShowTablesStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLDeclareItem_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLPartitionByHash_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLPartitionByRange_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLPartitionByList_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLSubPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLSubPartitionByHash_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLPartitionValue_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterDatabaseStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableConvertCharSet_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableDropPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableReOrganizePartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableCoalescePartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableTruncatePartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableDiscardPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableImportPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableAnalyzePartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableCheckPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableOptimizePartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableRebuildPartition_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableRepairPartition_ptr x)
  {
    return false;
  }

  bool visit(SQLSequenceExpr_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLMergeStatement_ptr x);

  // @Override
  bool visit(SQLSetStatement_ptr x)
  {
    return false;
  }

  SQLMethodInvokeExpr_list_ptr getFunctions()
  {
    return this->functions;
  }

  bool visit(SQLCreateSequenceStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableAddConstraint_ptr x);

  // @Override
  bool visit(SQLAlterTableDropIndex_ptr x);

  // @Override
  bool visit(SQLAlterTableDropPrimaryKey_ptr x);

  // @Override
  bool visit(SQLAlterTableDropKey_ptr x);

  // @Override
  bool visit(SQLDescribeStatement_ptr x);

  bool visit(SQLExplainStatement_ptr x);

  bool visit(SQLCreateMaterializedViewStatement_ptr x);

  bool visit(SQLReplaceStatement_ptr x);

  void statExpr(SQLExpr_ptr x);

  bool visit(SQLAlterFunctionStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLDropSynonymStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLAlterTypeStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLAlterProcedureStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLExprStatement_ptr x);

  // @Override
  bool visit(SQLDropTypeStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLExternalRecordFormat_ptr x)
  {
    return false;
  }

  bool visit(SQLCreateDatabaseStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLCreateTableGroupStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLDropTableGroupStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLShowDatabasesStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLShowColumnsStatement_ptr x);

  bool visit(SQLShowCreateTableStatement_ptr x);

  bool visit(SQLShowTableGroupsStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableSetOption_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLShowCreateViewStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLCreateRoleStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLDropRoleStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLShowViewsStatement_ptr x)
  {
    return false;
  }

  // @Override
  bool visit(SQLAlterTableExchangePartition_ptr x);

  bool visit(SQLDropCatalogStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLUnionQuery_ptr x);

  // @Override
  bool visit(SQLValuesTableSource_ptr x)
  {
    return false;
  }

  bool visit(SQLAlterIndexStatement_ptr x);

  bool visit(SQLShowIndexesStatement_ptr x);

  bool visit(SQLAnalyzeTableStatement_ptr x);

  bool visit(SQLExportTableStatement_ptr x);

  bool visit(SQLImportTableStatement_ptr x);

  bool visit(SQLCreateOutlineStatement_ptr x);

  bool visit(SQLDumpStatement_ptr x);

  bool visit(SQLDropOutlineStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLAlterOutlineStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLAlterTableArchivePartition_ptr x)
  {
    return true;
  }

  // @Override
  bool visit(HiveCreateTableStatement_ptr x)
  {
    return visit(std::dynamic_pointer_cast<SQLCreateTableStatement>(x));
  }

  // @Override
  bool visit(SQLCopyFromStatement_ptr x);

  // @Override
  bool visit(SQLCloneTableStatement_ptr x);

  // @Override
  bool visit(SQLSyncMetaStatement_ptr x)
  {
    return false;
  }

  SQLName_list_ptr getOriginalTables()
  {
    return originalTables;
  }

  // @Override
  bool visit(SQLUnique_ptr x);

  bool visit(SQLSavePointStatement_ptr x)
  {
    return false;
  }

  bool visit(SQLShowPartitionsStmt_ptr x);
};

class SchemaStatVisitor_OrderByStatVisitor
    : virtual public SQLASTVisitorAdapter,
      virtual public SchemaStatVisitor
{
public:
  SQLOrderBy_ptr orderBy;

  SchemaStatVisitor_OrderByStatVisitor(SQLOrderBy_ptr orderBy);

  SQLOrderBy_ptr getOrderBy()
  {
    return orderBy;
  }

  bool visit(SQLIdentifierExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLPropertyExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLIntegerExpr_ptr x)
  {
    return visitOrderBy(x);
  }
};

class SchemaStatVisitor_MySqlOrderByStatVisitor
    : virtual public MySqlASTVisitorAdapter,
      virtual public SchemaStatVisitor
{
public:
  SQLOrderBy_ptr orderBy;

  SchemaStatVisitor_MySqlOrderByStatVisitor(SQLOrderBy_ptr orderBy);

  SQLOrderBy_ptr getOrderBy()
  {
    return orderBy;
  }

  bool visit(SQLIdentifierExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLPropertyExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLIntegerExpr_ptr x)
  {
    return visitOrderBy(x);
  }
};

class SchemaStatVisitor_PGOrderByStatVisitor
    /*: virtual public PGASTVisitorAdapter*/
    : virtual public SchemaStatVisitor
{
public:
  SQLOrderBy_ptr orderBy;

  SchemaStatVisitor_PGOrderByStatVisitor(SQLOrderBy_ptr orderBy);

  SQLOrderBy_ptr getOrderBy()
  {
    return orderBy;
  }

  bool visit(SQLIdentifierExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLPropertyExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLIntegerExpr_ptr x)
  {
    return visitOrderBy(x);
  }
};

class SchemaStatVisitor_OracleOrderByStatVisitor
    : virtual public OracleASTVisitorAdapter,
      virtual public SchemaStatVisitor
{
public:
  SQLOrderBy_ptr orderBy;

  SchemaStatVisitor_OracleOrderByStatVisitor(SQLOrderBy_ptr orderBy);

  SQLOrderBy_ptr getOrderBy()
  {
    return orderBy;
  }

  bool visit(SQLIdentifierExpr_ptr x)
  {
    return visitOrderBy(x);
  }

  bool visit(SQLPropertyExpr_ptr x);

  bool visit(SQLIntegerExpr_ptr x)
  {
    return visitOrderBy(x);
  }
};
